/* Copyright (c) 2009-2010, Sean A.O. Harney <sharney3@gmail.com> */

#include "omf.h"


// returns with Random_handle datastructure filled in
bool random_init(Random_handle * handle, Random_src src)
{
    handle->src = src;
    handle->rand_r_state = time(NULL);	//seed pseudo rng
    // even if using dev, may still be used.

    if (src == RS_DEV_URANDOM || src == RS_DEV_RANDOM)
      {
	  char *path =
	      (src == RS_DEV_URANDOM ? PATH_DEV_URANDOM : PATH_DEV_RANDOM);
	  if ((handle->devfp = fopen(path, "r")) == NULL)
	    {
		perror(path);
		return false;
	    }
    } else if (src != RS_LIBC_RAND_R)
      {
	  fprintf(stderr, "random_init(): unknown source: %d", src);
	  return false;
      }

    return true;
}

void random_close(Random_handle * handle)
{
    if (handle->src == RS_DEV_URANDOM || handle->src == RS_DEV_RANDOM)
      {
	  fclose(handle->devfp);
	  handle->devfp = NULL;
      }
}
bool random_get_byte(Random_handle * handle, uint8_t * randbyte)
{
    return random_get_bytes(handle, randbyte, 1);
}

bool random_get_bytes(Random_handle * handle, uint8_t * randbytes,
		      size_t num_bytes)
{
    bool ret = true;
    size_t i;

    switch (handle->src)
      {
      case RS_DEV_RANDOM:
      case RS_DEV_URANDOM:
	  if (fread(randbytes, 1 /*byte */ , num_bytes /*nmemb */ ,
		    handle->devfp) != num_bytes)
	    {
		//dev file shouldn't have EOF, so must be error
		perror("random_get_byte(): fread()");
		ret = false;
	    }
	  break;
      case RS_LIBC_RAND_R:
	  for (i = 0; i < num_bytes; i++)
	      randbytes[i] = rand_r(&(handle->rand_r_state)) % 256;
	  //maybe 255?, to convert randint to randbyte
	  break;
      default:
	  fprintf(stderr, "random_get_byte(): unknown source: %d",
		  handle->src);
	  ret = false;
      }

    return ret;
}


// if both lb and ub = 0, then it uses the default bounds defined in random.h
bool random_get_random_amount_of_bytes(Random_handle * handle,
				       uint8_t * randbytes,
				       size_t * num_bytes, size_t lb,
				       size_t ub)
{
    int rand;
    size_t _lb = lb;
    size_t _ub = ub;

    if (lb == 0 && ub == 0)
      {
	  _lb = RANDOM_LENGTH_DEFAULT_LB;
	  _ub = RANDOM_LENGTH_DEFAULT_UB;
      }

    rand = rand_r(&(handle->rand_r_state));
    *num_bytes = (rand % (_ub + 1)) + _lb;	/* (lb,ub) inclusive. */

    debug2_printf("%d <= %d <= %d\n", _lb, *num_bytes, _ub);
    return random_get_bytes(handle, randbytes, *num_bytes);
}
